#!/usr/bin/env python

import screenlets

from screenlets import DefaultMenuItem
from screenlets.options import BoolOption
from screenlets.options import StringOption
from screenlets.options import FileOption
from screenlets.options import ImageOption

from ConfigParser import ConfigParser

import gtk
import wnck
import re
import os

import ApplicationIconWidget
from ApplicationIconWidget import ApplicationIconWidget

# Show list of application icons
# When clicking on icon, a new application is launched, or switching to next window of application's window, if already launched
# When doubleclicking, will always launch a new instance
# 
# based on WindowlistScreenlet (c) 2007 RYX (aka Rico Pfaus) <ryx@ryxperience.com>
#
# TODO:
#  add tooltips for icons with description of launched windows 
class ApplicationListScreenlet (screenlets.Screenlet):
	""" ApplicationListScreenlet."""
	
	# default meta-info for Screenlets
	__name__		= 'ApplicationListScreenlet'
	__version__		= '0.1'
	__author__		= 'vasyas (Vasyl Stashuk) 2010'
	__desc__		= __doc__
	
	# list of ApplicationIconWidget
	__application_icons	= None
	__tooltips		= None		# tooltips object
	__box 			= None		# content gtk.Box (HBox/Vbox)
	
	launchersDir = '/home/vasyas/launchers/1'
	vertical = False
	left = False
	
	icon_size 		= 32
	icon_spacing	= 5
	
	# constructor
	def __init__ (self, text="", **keyword_args):
		#call super (and don't make this a "Widget")
		screenlets.Screenlet.__init__(self, width=40, height=40, 
			is_widget=False, is_sticky=True, **keyword_args)
		# add HBox for children (TODO: optional: vbox)
		
		self.__application_icons = []

		# create tooltips
		self.__tooltips = gtk.Tooltips()
		# try to set wnck's client type to pager so that we correctly flag
		# that we are a tasklist - only available in libwnck-python >= 2.22
		try:
			wnck.set_client_type(wnck.CLIENT_TYPE_PAGER)
		except AttributeError:
			print "Error: Failed to set libwnck client type, window " \
				"activation may not work"
		
		self.add_options_group('General', 'General')
		self.add_option(BoolOption('General','vertical', 
			self.vertical, 'Expand Verticaly (restart req) ', 
			'Expand window list verticaly'))
		self.add_option(BoolOption('General','left', 
			self.left, 'Expand left (restart req)', 
			'Expand window list left'))
		
		# connect screen-signal handlers
		screen = wnck.screen_get_default()
		screen.connect("window_opened", self.window_opened)
		screen.connect("window_closed", self.window_closed)
		#screen.connect("application_opened", self.test_event)
		# screen.connect("window_stacking_changed", 
		#	self.window_stacking_changed)
		
		self.disable_option('scale')
		
		self.add_option(FileOption('General', 'launchersDir', self.launchersDir, 
								   'Directory with launchers', 'Where to look for launcher description files'))
		
	# ---------------------------------------------------------------------
	# public methods
	# ---------------------------------------------------------------------
	
	def on_init (self):
		if self.vertical == False:
			self.__box = gtk.HBox()
		else:
			self.__box = gtk.VBox()
			
		self.__box.show()
		self.__box.spacing = self.icon_spacing	# doesn't work!
		self.window.add(self.__box)
		self.add_default_menuitems(
			DefaultMenuItem.WINDOW_MENU | 
			DefaultMenuItem.PROPERTIES | 
			DefaultMenuItem.DELETE | DefaultMenuItem.QUIT | DefaultMenuItem.QUIT_ALL)

		self.__reload_applications()
			
	# returns the ApplicationIconWidget for the given WnckWindow (or NOne)
	def __get_application(self, wnckwin):
		if wnckwin == None or wnckwin.is_skip_tasklist():
			return None
		
		# try to find in window's list, if it's not a new window
		for icon in self.__application_icons:
			if icon.related_to(wnckwin):
				return icon
			
		return None
	
	def __reload_applications(self):
		for iw in self.__application_icons:
			iw.destroy()
			
		self.__application_icons = []
		
		files = os.listdir(self.launchersDir)
		
		for launcherFile in sorted(files):
			cfg = ConfigParser()
			cfg.read(self.launchersDir + '/' + launcherFile)
			
			self.__create_application(cfg.get('Entry 0', 'Name'), cfg.get('Entry 0', 'Exec'), cfg.get('Entry 0', 'Icon'))
			
		if len(self.__application_icons) == 0:
			self.__create_application('bash', '/bin/bash', 'not-found')
			 
	
	def __create_application(self, name, command, iconPath):
		#load icon
		try:
			icon = gtk.gdk.pixbuf_new_from_file(iconPath)
		except Exception,ex:
			print "Error loading image: %s" % ex
			icon = gtk.gdk.pixbuf_new_from_file(self.get_screenlet_dir() + '/icon-default.png')
		
		icon = icon.scale_simple(self.icon_size, self.icon_size, gtk.gdk.INTERP_BILINEAR)

		# create widget
		iw = ApplicationIconWidget(self.icon_size + self.icon_spacing, self.icon_size + 4, name, command, icon)
		
		self.__box.pack_start(iw, expand=False, fill=False)
		iw.show()
		
		# add window's name as tooltip
		self.__tooltips.set_tip(iw, name)
		
		# save into list
		self.__application_icons.append(iw)
		
		# set size to correctly draw shape mask
		if self.vertical:
			self.height = len(self.__application_icons) * (self.icon_size +	self.icon_spacing)
			self.width = 40
			
			if self.left:
				self.y = self.y - (self.icon_size +	self.icon_spacing)
		else:
			self.width = len(self.__application_icons) * (self.icon_size + self.icon_spacing)
			self.height = 40
			if self.left and self.has_started and self.window.window.is_visible():
				self.x = self.x - (self.icon_size +	self.icon_spacing)
				
		self.update_shape()
	
	# ---------------------------------------------------------------------
	# Event-handling methods
	# ---------------------------------------------------------------------
	def on_quit(self):
		if self.left:
			if not self.vertical : self.x = self.x + self.width
			else:self.y = self.y + self.height 
		
		
	# called when a new wnckwin is opened
	def window_opened (self, screen, wnckwin):
		icon = self.__get_application(wnckwin)
		
		print "Window opened: " + wnckwin.get_application().get_name() + ", icon " + ("Unknown" if icon == None else icon.get_name())
		
		if icon == None: return
			
		icon.open_window(wnckwin)
	
	# called when a wnckwin is closed
	def window_closed (self, screen, wnckwin):
		icon = self.__get_application(wnckwin)
		
		print "Window closed: icon " + ("Unknown" if icon == None else icon.get_name()) 
		
		if (icon == None): return
			
		icon.close_window(wnckwin)
	
	# ---------------------------------------------------------------------
	# Drawing methods
	# ---------------------------------------------------------------------
	
	def on_draw_shape (self,ctx):
		#if self.theme:
		#	self.theme['windowlist-bg.svg'].render_cairo(ctx)
		# render bg shape according to window size
		size = self.window.size_request()
		ctx.rectangle(0, 0, size[0], size[1])
		ctx.set_source_rgba(1, 1, 1, 1)
		ctx.fill()


	def __setattr__ (self, name, value):
		screenlets.Screenlet.__setattr__(self, name, value)
		
		if name == 'vertical' or name == 'left':
			self.redraw_canvas()
			
		if name == "launchersDir" and self.has_started:
			self.__reload_applications()
			self.redraw_canvas()
			
if __name__ == "__main__":
	import screenlets.session
	screenlets.session.create_session(ApplicationListScreenlet)
